/*
// Licensed to Julian Hyde under one or more contributor license
// agreements. See the NOTICE file distributed with this work for
// additional information regarding copyright ownership.
//
// Julian Hyde licenses this file to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
 */
package org.olap4j.metadata;

import org.olap4j.OlapException;
import org.olap4j.mdx.ParseTreeNode;

import java.util.List;

/**
 * <code>Member</code> is a data value in an OLAP Dimension.
 * 
 * @author jhyde
 * @since Aug 22, 2006
 */
public interface Member extends MetadataElement {
	/**
	 * Returns the children of this Member, indexed by name.
	 * 
	 * <p>
	 * If access-control is in place, the list does not contain inaccessible children.
	 * 
	 * <p>
	 * If the member has no children, returns an empty list: the result is never null.
	 * 
	 * <p>
	 * The caller should assume that the list is immutable; if the caller modifies the list, behavior is undefined.
	 * </p>
	 * 
	 * @see org.olap4j.OlapDatabaseMetaData#getMembers
	 * 
	 * @return children of this member
	 * 
	 * @throws OlapException
	 *             if database error occurs
	 */
	NamedList<? extends Member> getChildMembers() throws OlapException;

	/**
	 * Returns the number of children this Member has.
	 * 
	 * <p>
	 * This method has the same effect as <code>getChildMembers().size()</code>, but is typically less expensive.
	 * 
	 * @return number of children
	 * 
	 * @throws OlapException
	 *             if database error occurs
	 */
	int getChildMemberCount() throws OlapException;

	/**
	 * Returns the parent of this Member, or null if it has no parent.
	 * 
	 * @return Parent member, or null if member has no parent
	 */
	Member getParentMember();

	/**
	 * Returns the Level of this Member.
	 * 
	 * <p>
	 * Never returns null.
	 * </p>
	 * 
	 * @return Level which this Member belongs to
	 */
	Level getLevel();

	/**
	 * Returns the Hierarchy of this Member.
	 * 
	 * <p>
	 * Never returns null. Result is always the same as <code>getLevel().getHierarchy()</code>.
	 * 
	 * @return Hierarchy which this Member belongs to
	 */
	Hierarchy getHierarchy();

	/**
	 * Returns the Dimension of this Member.
	 * 
	 * <p>
	 * Never returns null. Result is always the same as <code>getLevel().getHierarchy().getDimension()</code>.
	 * 
	 * @return Dimension which this Member belongs to
	 */
	Dimension getDimension();

	/**
	 * Returns the type of this Member.
	 * 
	 * <p>
	 * Never returns null.
	 * </p>
	 * 
	 * @return What kind of member this is
	 */
	Type getMemberType();

	/**
	 * Returns whether this Member represents the aggregation of all members in its Dimension.
	 * 
	 * <p>
	 * An 'all' member is always the root of its Hierarchy; that is, its parent member is the null member, and
	 * {@link Hierarchy#getRootMembers()} returns the 'all' member and no others. Some hierarchies do not have an 'all'
	 * member.
	 * 
	 * @see Hierarchy#hasAll()
	 * 
	 * @return whether this Member is the 'all' member of its Dimension
	 */
	boolean isAll();

	/**
	 * Enumeration of types of members.
	 * 
	 * <p>
	 * The values are as specified by XMLA, plus the additional {@link #NULL} value not used by XMLA. For example, XMLA
	 * specifies <code>MDMEMBER_TYPE_REGULAR</code> with ordinal 1, which corresponds to value {@link #REGULAR}.
	 * 
	 * <p>
	 * The {@link #FORMULA} value takes precedence over {@link #MEASURE}. For example, if there is a formula
	 * (calculated) member on the Measures dimension, it is listed as <code>FORMULA</code>.
	 */
	enum Type {
		UNKNOWN(0), REGULAR(1), ALL(2), MEASURE(3), FORMULA(4),
		/**
		 * Indicates that this member is its hierarchy's NULL member (such as is returned by the expression
		 * <code>[Gender]&#46;[All Gender]&#46;PrevMember</code>, for example).
		 */
		NULL(5);

		private Type(int ordinal) {
			assert ordinal == ordinal();
		}
	}

	/**
	 * Returns whether <code>member</code> is equal to, a child of, or a descendent of this Member.
	 * 
	 * @param member
	 *            Member
	 * @return Whether the given Member is a descendent of this Member
	 */
	boolean isChildOrEqualTo(Member member);

	/**
	 * Returns whether this member is calculated using a formula.
	 * 
	 * <p>
	 * Examples of calculated members include those defined using a <code>WITH MEMBER</code> clause in an MDX query (
	 * {@link #getMemberType()} will return {@link Type#FORMULA} for these), or a calculated member defined in a cube.
	 * 
	 * @return Whether this Member is calculated
	 * 
	 * @see #isCalculatedInQuery()
	 */
	boolean isCalculated();

	/**
	 * Returns the solve order of this member in a formula.
	 * 
	 * @return solve order of this Member
	 */
	int getSolveOrder();

	/**
	 * Expression by which this member is derived, if it is a calculated member. If the member is not calulated, returns
	 * null.
	 * 
	 * @return expression for this member
	 */
	ParseTreeNode getExpression();

	/**
	 * Returns array of all members which are ancestor to <code>this</code>.
	 * 
	 * @return ancestor Members
	 */
	List<Member> getAncestorMembers();

	/**
	 * Returns whether this member is computed from a <code>WITH MEMBER</code> clause in an MDX query. (Calculated
	 * members can also be calculated in a cube.)
	 * 
	 * @return Whether this member is calculated in a query
	 * 
	 * @see #isCalculated()
	 */
	boolean isCalculatedInQuery();

	/**
	 * Returns the value of a given property.
	 * 
	 * <p>
	 * Returns null if the property is not set.
	 * </p>
	 * 
	 * <p>
	 * Every member has certain system properties such as "name" and "caption" (the full list is described in the
	 * {@link org.olap4j.metadata.Property.StandardMemberProperty} enumeration), as well as extra properties defined for
	 * its Level (see {@link Level#getProperties()}).
	 * </p>
	 * 
	 * @param property
	 *            Property
	 * 
	 * @return formatted value of the given property
	 * 
	 * @see #getPropertyFormattedValue(Property)
	 * 
	 * @throws OlapException
	 *             if database error occurs
	 */
	Object getPropertyValue(Property property) throws OlapException;

	/**
	 * Returns the formatted value of a given property.
	 * 
	 * <p>
	 * Returns null if the property is not set.
	 * </p>
	 * 
	 * <p>
	 * Every member has certain system properties such as "name" and "caption" (the full list is described in the
	 * {@link org.olap4j.metadata.Property.StandardMemberProperty} enumeration), as well as extra properties defined for
	 * its Level (see {@link Level#getProperties()}).
	 * </p>
	 * 
	 * @param property
	 *            Property
	 * 
	 * @return formatted value of the given property
	 * 
	 * @see #getPropertyValue(Property)
	 * 
	 * @throws OlapException
	 *             if database error occurs
	 */
	String getPropertyFormattedValue(Property property) throws OlapException;

	/**
	 * Sets a property of this member to a given value.
	 * 
	 * <p>
	 * Every member has certain system properties such as "name" and "caption" (the full list is described in the
	 * {@link org.olap4j.metadata.Property.StandardMemberProperty} enumeration), as well as extra properties defined for
	 * its Level (see {@link Level#getProperties()}).
	 * </p>
	 * 
	 * @param property
	 *            property
	 * 
	 * @param value
	 *            Property value
	 * 
	 * @throws OlapException
	 *             if the value not valid for this property (for example, a String value assigned to a Boolean property)
	 */
	void setProperty(Property property, Object value) throws OlapException;

	/**
	 * Returns the definitions of the properties this member may have.
	 * 
	 * <p>
	 * For many providers, properties are defined against a Level, so result of this method will be identical to
	 * <code>member.getLevel().{@link Level#getProperties() getProperties}()</code>.
	 * 
	 * @return properties of this Member
	 */
	NamedList<Property> getProperties();

	/**
	 * Returns the ordinal of the member.
	 * 
	 * @return ordinal of this Member
	 */
	int getOrdinal();

	/**
	 * Returns whether this member is 'hidden', as per the rules which define a ragged hierarchy.
	 * 
	 * @return whether this member is a hidden member of a ragged hierarchy
	 */
	boolean isHidden();

	/**
	 * Returns the depth of this member.
	 * 
	 * <p>
	 * In regular hierarchies, this is as the same as the level's depth, but in parent-child and ragged hierarchies the
	 * value may be different.
	 * </p>
	 * 
	 * @return depth of this Member
	 */
	int getDepth();

	/**
	 * Returns the system-generated data member that is associated with a non-leaf member of a dimension.
	 * 
	 * <p>
	 * Returns this member if this member is a leaf member, or if the non-leaf member does not have an associated data
	 * member.
	 * </p>
	 * 
	 * @return system-generated data member
	 */
	Member getDataMember();

	/**
	 * Enumeration of tree operations which can be used when querying members.
	 * 
	 * <p>
	 * Some of the values are as specified by XMLA. For example, XMLA specifies MDTREEOP_CHILDREN with ordinal 1, which
	 * corresponds to the value {@link #CHILDREN}.
	 * 
	 * @see org.olap4j.OlapDatabaseMetaData#getMembers
	 */
	public enum TreeOp implements XmlaConstant {
		/**
		 * Tree operation which returns only the immediate children.
		 */
		CHILDREN(1, "Tree operation which returns only the immediate children."),

		/**
		 * Tree operation which returns members on the same level.
		 */
		SIBLINGS(2, "Tree operation which returns members on the same level."),

		/**
		 * Tree operation which returns only the immediate parent.
		 */
		PARENT(4, "Tree operation which returns only the immediate parent."),

		/**
		 * Tree operation which returns itself in the list of returned rows.
		 */
		SELF(8, "Tree operation which returns itself in the list of returned " + "rows."),

		/**
		 * Tree operation which returns all of the descendants.
		 */
		DESCENDANTS(16, "Tree operation which returns all of the descendants."),

		/**
		 * Tree operation which returns all of the ancestors.
		 */
		ANCESTORS(32, "Tree operation which returns all of the ancestors.");

		private final int xmlaOrdinal;
		private String description;

		private static final Dictionary<TreeOp> DICTIONARY = DictionaryImpl.forClass(TreeOp.class);

		/**
		 * Per {@link org.olap4j.metadata.XmlaConstant}, returns a dictionary of all values of this enumeration.
		 * 
		 * @return Dictionary of all values
		 */
		public static Dictionary<TreeOp> getDictionary() {
			return DICTIONARY;
		}

		private TreeOp(int xmlaOrdinal, String description) {
			this.xmlaOrdinal = xmlaOrdinal;
			this.description = description;
		}

		public String xmlaName() {
			return "MDTREEOP_" + name();
		}

		public String getDescription() {
			return description;
		}

		public int xmlaOrdinal() {
			return xmlaOrdinal;
		}
	}
}

// End Member.java
